#include "AreaLight.h"
#include "material.h"
#include "sampler.h"
#include "result.h"
#include "Ray.h"
#include "World.h"
#include "iostream"
#include <cfloat>
#include <random>
#include <array>

mray::AreaLight::~AreaLight()
{
	delete m_spl;
}

mray::vec3 mray::AreaLight::Illuminate(const Result& result) const
{
	vec3 color;
	for(int i = 0; i < m_spl->m_nSamples; i++){
		vec2 sp = m_spl->GetSample(i);
		sp *= 2.f;
		sp -= vec2(1.f, 1.f);
		vec3 p = m_pos + m_right*(sp.x*m_halfw) + m_up*(sp.y*m_halfh);
		vec3 d = p-result.p;
		//if back to object
		if(d * m_look > 0.f) break;
		float dis = d.LengthAndNorm();
		if(m_castShadow){
			Ray shadowRay(result.p, d);
			if(result.m_pWorld->Hit(shadowRay))
				if(shadowRay.m_mint < dis-Bias)
					continue;
		}
		float atten = m_atten.CalcAtten(dis);
		float pdf = PDF(-d);
		color += result.pMtl->Shade(d, m_color*(atten*pdf), result);
	}
	color /= (float)(m_spl->m_nSamples);
	return color;
}

bool mray::AreaLight::Hit(Ray& ray, Result* pResult) const
{
	//case invisible , it will not be located in objlist
	return Rectangle::Hit(ray, pResult);
}

float mray::AreaLight::PDF(const vec3& wi) const
{
	//TODO lambert pdf
	return m_look * wi * INV_PI;
}

mray::AreaLight::AreaLight(const Rectangle& rect, BaseSampler* pSpl, const vec3& color, bool castShdow, bool visible):
	BaseLight(color, castShdow), Rectangle(rect), m_visible(visible), m_spl(pSpl){}